<?php

declare (strict_types = 1);

namespace app\common\service\user;

use app\common\exception\AdminException;
use app\common\repository\user\UserRepository;
use app\common\service\BaseService;
use app\common\service\FriendsService;
use app\common\service\SmsService;
use app\common\service\UserPreferenceService;
use app\common\service\wechat\WeChatService;
use app\common\util\JwtUtil;
use think\facade\Cache;
use think\facade\Request;
use Zhuzhichao\IpLocationZh\Ip;

class UserService extends BaseService
{
    public function __construct(UserRepository $repository)
    {
        $this->repository = $repository;
    }

    /**
     * 获取用户列表
     *
     * @param array $params
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     */
    public function getList(array $params = []): array
    {
        [$page, $pageSize] = $this->getPaginationParams();
        $where = [];
        if(!empty($params['username'])){
            $where[] = ['username', 'like', '%'.$params['username'].'%'];
        }
        if(!empty($params['nickname'])){
            $where[] = ['nickname', 'like', '%'.$params['nickname'].'%'];
        }
        return $this->repository->paginate($where, ['id' => 'desc'], $page, $pageSize);
    }

    /**
     * 获取用户详情信息
     *
     * @param $id
     * @return \app\common\model\BaseModel|array|mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getInfo($id): mixed
    {
        return $this->repository->getOne($id);
    }

    /**
     * 创建用户信息
     *
     * @param array $data
     * @return \think\Collection|\app\common\model\BaseModel|array
     * @throws \Exception
     */
    public function create(array $data): \think\Collection|\app\common\model\BaseModel|array
    {
        if(!empty($params['password'])){
            $data['password'] = password_hash($params['password'], PASSWORD_DEFAULT);
        }
        return $this->repository->save($data);
    }

    /**
     * 更新用户信息
     *
     * @param array $data
     * @param $id
     * @return \app\common\model\BaseModel|bool|int
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function update(array $data, $id)
    {
        if(empty($id)) {
            throw new AdminException('ID 不能为空');
        }
        if(!empty($data['password'])) {
            $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
        }
        return $this->repository->update($data, $id);
    }

    /**
     * 删除用户信息
     *
     * @param $id
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function delete($id): bool
    {
        return $this->repository->delete($id);
    }

    /**
     * 用户登录
     *
     * @param $params
     * @return string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function login($params): string
    {
        // 验证码验证
        if($params['code'] !== '123456') {
            throw new AdminException('验证码错误', 422);
        }

        $userInfo = $this->repository->getOne(['phone' => $params['phone']]);

        // 用户不否存在则注册
        if(!$userInfo) {
            return $this->register($params['phone']);
        } else {
            $userInfo['ip'] = Request::ip();
            $this->repository->update(['ip' => $userInfo['ip']], $userInfo['id']);
        }

        // 生成token
        return JwtUtil::generateToken($userInfo->id, 'user');
    }

    /**
     * 用户注册
     *
     * @param $phone
     * @return string
     * @throws \Exception
     */
    public function register($phone): string
    {
        $data['id'] = get_id();
        $data['phone'] = $phone;
        $data['status'] = 0;
        $data['ip'] = Request::ip();
        $userInfo = $this->repository->save($data);
        if($userInfo) {
            // 成功注册返回用户token
            return JwtUtil::generateToken($userInfo->id, 'user');
        } else {
            throw new AdminException('注册失败，请重试');
        }
    }

    /**
     * 发送验证码
     *
     * @param $phone
     * @return array|string
     */
    public function sendCode($phone): array|string
    {
        $smsService = app()->make(SmsService::class);
        return $smsService->send($phone);
    }

    /**
     * 微信授权登录
     *
     * @param $params
     * @return string 返回 JWT Token
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function wechatLogin($params): string
    {
        if (empty($params['code'])) {
            throw new AdminException('缺少必要的code参数', 422);
        }

        // 通过微信提供的code换取access_token和openid
        $wechatService = app()->make(WechatService::class);
        $result = $wechatService->getAccessTokenAndOpenId($params['code']);

        if (isset($result['errcode']) && $result['errcode'] != 0) {
            throw new AdminException('微信认证失败: ' . $result['errmsg'], 422);
        }

        // 检查用户是否存在
        $userInfo = $this->repository->getOne(['wechat_openid' => $result['openid']]);

        if (!$userInfo) {
            // 如果用户不存在，则注册新用户
            $data = [
                'wechat_openid' => $result['openid'],
                'status' => 0,
                'ip' => Request::ip(),
            ];

            $userInfo = $this->repository->save($data);
        } else {
            // 更新用户信息中的IP地址
            $userInfo['ip'] = Request::ip();
            $this->repository->update(['ip' => $userInfo['ip']], $userInfo['id']);
        }

        // 生成JWT token
        return JwtUtil::generateToken($userInfo->id, 'user');
    }

    /**
     * 实名认证
     *
     * @param $user_id
     * @param $real_name
     * @param $id_card
     * @return array|\app\common\model\BaseModel|bool|int
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function realNameAuth($user_id, $real_name, $id_card): array|\app\common\model\BaseModel|bool|int
    {
        // 调用接口验证身份证二要素通过后执行以下操作

        // 检查身份证号码长度是否合法
        $length = strlen($id_card);
        if ($length !== 18 && $length !== 15) {
            throw new AdminException('身份证号码长度不合法', 422);
        }

        // 提取出生日期
        if ($length === 18) {
            $birthDateStr = substr($id_card, 6, 8); // 提取第 7-14 位
            $genderCode = substr($id_card, 16, 1);  // 提取第 17 位
        } else { // 长度为 15 位
            $birthDateStr = '19' . substr($id_card, 6, 6); // 补全年份
            $genderCode = substr($id_card, 14, 1);         // 提取第 15 位
        }

        // 格式化出生日期
        $birthYear = substr($birthDateStr, 0, 4);
        $birthMonth = substr($birthDateStr, 4, 2);
        $birthDay = substr($birthDateStr, 6, 2);
        $birthDate = "$birthYear-$birthMonth-$birthDay";

        // 判断性别
        $gender = ($genderCode % 2 === 0) ? 0 : 1;

        // 计算年龄
        $currentYear = (int)date('Y');
        $currentMonth = (int)date('m');
        $currentDay = (int)date('d');

        $age = $currentYear - $birthYear;
        if ($currentMonth < $birthMonth || ($currentMonth == $birthMonth && $currentDay < $birthDay)) {
            $age--; // 如果当前日期还未到生日，则减 1 岁
        }

        $data = [
            'birth_date' => $birthDate,
            'sex' => $gender,
            'age' => $age,
            'real_name' => $real_name,
            'id_card' => $id_card,
            'profile_complete' => 1
        ];

        return $this->repository->update($data, $user_id);
    }

    /**
     * 保存用户信息
     *
     * @param $data
     * @param $user_id
     * @return \app\common\model\BaseModel|bool|int
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function saveUserInfo($data, $user_id): \app\common\model\BaseModel|bool|int
    {
        $cacheTag = "user_info_tag:$user_id";
        $userInfo = $this->repository->getOne($user_id);
        Cache::tag($cacheTag)->clear();
        return $this->repository->update($data, $userInfo['id']);
    }

    /**
     * 获取用户信息
     *
     * @param $user_id
     * @param array $fields
     * @return \app\common\model\BaseModel|array|mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getUserInfo($user_id, array $fields = ['*']): mixed
    {
        // 如果字段列表包含 '*'，替换为默认字段列表
        if (in_array('*', $fields)) {
            $fields = [
                'id',
                'nickname',
                'avatar',
                'phone',
                'email',
                'ip',
                'sex',
                'desc',
                'age',
                'money',
                'status',
                'photos',
                'birth_day',
                'profile_complete',
                'followers_count',
                'following_count',
                'area_code',
                'city_code',
                'province_code',
                'address_id'
            ];
        }

        // 获取当前登录用户 ID
        $currentUserId = request()->userInfo['user_id'];

        // 动态调整字段列表
        if ($currentUserId !== $user_id) {
            // 非当前用户访问，移除敏感字段
            $fields = array_diff($fields, ['phone', 'email', 'ip']);
        }

        // 动态生成缓存键
        $cacheKey = "user_info:$user_id:" . md5(implode(',', $fields));
        $cacheTag = "user_info_tag:$user_id";

        // 如果缓存存在，直接返回
        if (Cache::has($cacheKey)) {
            return Cache::get($cacheKey);
        }

        // 查询用户信息
        $userInfo = $this->repository->getOne($user_id, $fields);
        if(array_key_exists('ip', $userInfo->toArray())) {
            $userInfo['province'] = Ip::find($userInfo['ip'])[1] ?? '未知';
        }
        if ($userInfo) {
            // 缓存五分钟
            Cache::tag($cacheTag)->set($cacheKey, $userInfo, 300);
        }

        return $userInfo;
    }

    /**
     * 批量获取用户信息
     *
     * @param $user_ids
     * @param array $filed
     * @return array
     */
    public function batchGetUserInfo($user_ids, array $filed = ['*']): array
    {
        return $this->repository->getByWhere([
            ['id', 'in', $user_ids]
        ], [], $filed)->toArray();
    }

    /**
     * 调整计数
     *
     * @param $user_id
     * @param $field
     * @param $type
     * @param int $step
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function adjustCount($user_id, $field, $type, int $step = 1): bool
    {
        return $this->repository->setInc($user_id, $field, $type, $step);
    }


    /**
     * 获取心动匹配用户列表
     *
     * @param string $user_id
     * @param array $where
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getUserList(string $user_id, array $where = []): array
    {
        [$page, $pageSize] = $this->getPaginationParams();
        $cacheKey = "people_nearby:$page:$pageSize:$user_id";
        if(Cache::has($cacheKey)) {
            return Cache::get($cacheKey);
        }
        $data = $this->repository->getUserList($user_id, $where, $page, $pageSize);
        Cache::set($cacheKey, $data, 300);
        return $data;
    }

    /**
     * 获取用户相互状态
     *
     * @param $user_id
     * @param $target_user_id
     * @return array|int[]
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getMutualState($user_id, $target_user_id): array
    {
        $status = [
            'status' => 0,
        ];
        $friendsService = app()->make(FriendsService::class);
        $res = $friendsService->isFriendship($user_id, $target_user_id);
        if($res) {
            $status = [
                'status' => 2, // 互相关注
            ];
        } else {
            $userPreferenceService = app()->make(UserPreferenceService::class);
            $PreferenceInfo = $userPreferenceService->getInfo([
                'user_id' => $user_id,
                'target_user_id' => $target_user_id,
                'preference' => 'like'
            ]);

            if($PreferenceInfo) {
                $status = [
                    'status' => 1, // 当前用户已关注目标用户
                ];
            }
        }
        return $status;
    }
}